{
      {   //todo vue2 概念
            /* 
              脚手架里主要文件和作用?
            1. node_modules – 都是下载的第三方包
            2. public/index.html –浏览器运行的网页
            3. src/main.js –webpack打包的入口
            4. src/App.vue –Vue页面入口
            5. package.json –依赖包列表文件
        
          mainjs和App.vue,以及index.html作用和关系?
            1. main.js -项目打包主入口- Vue初始化
            2. App.vue - Vue页面主入口
            3. index.html -浏览器运行的文件
            4. App.vue => main.js => index.html
        
          改配置由 webpack.config.js  换成  vue.config.js 
        
             vue 开发环境 npm yarn 创建 + 启动 就OK 
             
             
        
        &nbsp;
        <！--不换行空格，全称是No-Break Space。它是按下space键产生的空格。此空格占据宽度受字体影响明显而强烈。-->
        &ensp;
        <！--半角空格，全称是En Space。占半个中文字符的宽度。-->
        &emsp;
        <！--全角空格，全称是Em Space。占一个中文宽度。-->
        &thinsp;
        <！--窄空格，全称是Thin Space。是em的六分之一宽。-->
        
        
        
        
        
        
        ~  快捷键  Ctrl+a Ctrl+c  然后f3贴图  
        
        工程化开发方式：在webpack环境中开发Vue   vue 是渐进式JS框架
        
        1、安装 yarn  npm  vue框架  （global 全局安装）
              yarn global add @vue/cli    @vue/cli是Vue官方提供的一个全局模块包(得到vue命令), 此包用于创建脚手架项目
              npm i -g @vue/cli
        
        2、查询是否安装成功
              vue -V
        
        3、创建项目
              vue create vuecode   注意：要选 vue2
        
        4、创建项目成功后会多出一个 文件包要继续进入
              cd "vuecil-demo"
        
        5、进入脚手架项目下, 启动内置的热更新本地服务器
            yarn serve 或  npm run serve
        
        
        
        
        
        6、在good中安装 vue.js devtools 插件   vue数据才能显示到页面中
          mvvm ：  m 数据层  > v 视图层 > vm 源码底层处理
                model : 数据层 script
                view  : 视图层 template
                viewModel :  源码 监听数据改变 值赋予到页面 
        
                数据改变 => 视图   不用操作 DOM
                试图改变 => 数据    v-model
        
            
            */
      }
      {   //todo  一、vue语法
            /* 
         
               1、插值表达式   {{ msg }}    msg 哪来的，需要在data中提供该数据，这样template模板中就可以直接使用该数据了
                     data(){
                           return {
                                 数据
                           }
                     }
               2、动态设置属性的值     
                     v-bind:属性名="值"  
                     简写   :属性名="值"
         
               3、注册事件
                     v-on:事件名="少量代码"
                     v-on:事件名="函数名"
                     v-on:事件名="函数名(参数)"
                     
                     简写    @事件名="函数名(参数)"
         
                     函数 在哪提供    methods: { 提供函数 }
         
               4、事件对象的获取
                     无传参的话，通过e获取
                     有传参的话，$event 传参过去 进行接收
         
         
               !5、事件修饰符     
                     .stop -阻止事件冒泡
                     .prevent -阻止默认行为
                     .once - 只执行一次事件处理函数 
         
                     注意：可以在事件后面加多个修饰符 例如：@click.prevent.stop="one"
                                          键盘事件也一样  @keyup.delete.enter.esc="elete"
                     给键盘事件添加修饰符 ：
                             @kuyup.enter - 检测回车按键
                             @keyup.esc   - 检测返回按键
         
               !6、split  join('') reverse()
                      split方法主要用于将一个字符串分隔成多个字符串数组
                      join 字符串数组转字符串 并去除双引号
                      reverse 翻转数组中元素
         
         
               !7、v-model: 暂时只能用在表单标签上 input 
                  v-moder双向数据绑定  数据 =>视图=>数据
                     暂时只能用在表单标签上 input
                  v-model有什么作用?
                     把vue的数据变量和表单的value属性双向绑定在一起
                     * 语法：v-model="vue数据变量"
         
                  1、v-model:修饰符:
                                  .nubmber：以parseFloat转成数字类型 转成数值类型赋予给Vue数据变量
                                  .trim -去除左右两边空格后把值赋予给Vue数据变量
                                  .lazy -等表单失去焦点,才把值赋予给Vue数据变量
               Vue针对v-mode|有哪些修饰符,提高我们编程效率?
                                 1. .number -转成数值类型赋予给Vue数据变量
                                 2. .trim -去除左右两边空格后把值赋予给Vue数据变量
                                 3. .lazy -等表单失去焦点,才把值赋予给Vue数据变量
         
                  2、复选框, v-model的变量值:  非数组 - 关联的是复选框的checked属性
                                              数组   - 关联的是复选框的value属性
                                             
                     下拉框 v-model 设置在 下拉菜单要绑定在 下拉框 select上
         
                  
         
                !8、v-text   v-html   
                     v-html：可以解析标签
                     v-text: 不能解析标签
                     注意: v-text或v-html会覆盖插值表达式 
                           {{}} :插值表达式不能覆盖内容
                     
                   ~ v-if  、v-show   
                      语法: v-show 或者 v-if
                            v-show="vue变量"
                            v-if="vue变量"
                      原理：
                            v-show隐藏: 采用display:none   // 频繁切换      比如：反回顶部的显示与隐藏
                            v-if隐藏:   采用从DOM树直接移除 // 移除          比如：vip标识 要么显示要么不显示
                      总结：
                      vue如何控制标签显示/隐藏
                            v-show或v-if,给变量赋予true/false,显示/隐藏
                      区别是什么?
                            v-show是用css方式隐藏标签
                            v-if直接从DOM树.上移除
                            v-if可以配合v-else或者v- else-if使用
         
         
                   vi-if 与 v-else-if 连起来使用
         
               !9、v-for例 ： 
                           语法1：  v-for="(值变量 ，值索引) in 目标结构"   
                           语法2：  v-for=" 值变量  in 目标结构"
         
                           遍历对象
                           语法3：  v-for= "值变量 in 对象" 
                           遍历数字
                           语法4：  v-for ="值变量 in 固定数字 "
         
         
                 <li v-for="(item, index) in arr" :key="index">
                 <li v-for="item in stuArr" :key="item.id">
                 注意kay:是用来遍历
         
                v-for如何循环列表?
                                 1. 谁想循环就把v-for写谁身上
                                 2. v-for=“(值变量, 索引变量) in 目标结构”-一定注意in两边必须有空格
                                 3. 可以遍历数组 / 对象 / 固定数字
         
                v-for更新检测   $set
                           参数1: 更新目标结构
                           参数2: 更新位置
                           参数3: 更新值
                this.$set(this.arr, 0, 1000);
                          数据    位置  类名：值
               
               ~ key	key的最终结论： v-for的时候，必须要带上key，提高渲染更新性能
                     唯一的id或索引（类型必须是字符串 或 数字，不能是其他类型）
         
               因为 vue 在更新渲染 dom 的时候是根据新旧 dom 数进行对比的，使 
               用 key 来给每个节点做一个唯一标识，Diff 算法就可以正确的识别此节 
               点，找到正确的位置区插入新的节点
         
         
               !10、.split()  join()        splice() 数组方法与  Slice()
                     .split() 将一个字符串分割为子字符串，将结果作为字符串数组返回，若字符串中存在多个分割符号，亦可分割。
                     Join() 字符串数组 转 字符串
                区别
                     Splice  直接操作原数组，    会改变原数组 ,返回增加或删除的值，可以用于往数组中插入新的值
                     Slice   可用于字符串的截取、不会改变原数组  返回截取的数组片段 只能用于获取部分数组片段。 
                总结
                     1. 如果想截取原数组的某些数组片段，用slice，取返回值
                     2. 想增加或删除原数组中的某些值，用splice
                     3. 字符串的截取，用slice
         
                           下标 ，只留前三个  
                     slice（0  ,  3） 截取
         
                         位置 删除的个数 添加的元素
                     splice(3, 0, "新元素");       在数组间第三个添加数据
         
                             下标  个数
                     splice(index, 1);             遍历删除数组方法   day2购物车案例
         
                     unshift( )  头部添加
                     shift( )       
                     push( )     尾部添加
                     pop( )
         
                 
         
         
                    join（）
                    splice( )   
                    
                    sort ( )    以字母顺序对数组重新排列
                    reverse ( ) 翻转   
            
            
            */
      }
      {   //todo  Day-2
            /* 
                
                  !1、动态class   动态style
                        动态class    :class="{ css类名: 值, 类名: 值 }"
                                                                    <td :class="{ red: item.price > 100 }">{{ item.price }}</td>
                        动态style	 :style="{ css属性名: 属性值, css属性名: 属性值 }"
                                                                  style="{ backgroundColor: 'red', color: 'pink' }"
                        可以使用多个样式用逗号隔开
        
                  !2、过滤器  filters
                        全局： Vue.filter('过滤器名字', (val) => { val 就是要处理的数据，把处理后的结果给return返回出去 })
                        局部： .vue文件中， 在 filters: { 过滤器名字(val){return 处理后的值} }
        
                        ~使用过滤器：只能用在 插值表达式 和  v-bind的动态属性中
                        ~处理一个值后返回另一个值  例：输入 小写hello 变大写 HELLO
                        
                        传参
                              {{ msg | 过滤器名字(参数) }}
                        使用多个过滤器
                              {{ msg | 过滤器名字(参数) | 过滤器2 }}
                        
                        * title:鼠标长停
                        * toUpperCase 方法用于把字符串转换为大写
                        
                  
                  !3、计算属性: computed
                             计算属性 ：一个变量的结果依赖于其他的变量计算出来
                             优势  ： 把计算的结果给缓存起来
                             提供计算属性的时候，写函数形式，当在使用计算属性的时候，当属性使用 普通使用可以 {{在插值表达式里使用}}
                        
                        computed: {
                        ~ 下面函数写法，等价是提供get，没有提供set，修改计算属性值的时候，会报错
                        计算属性名(){
                              return
                        },
        
                        ! 完整写法
                        给 "赋值" 触发set方法
                        computed:{
                              set(val) {
                                    console.log(val);
                                    就是要修改后的结果
                              },
                              使用full的值触发get方法
                              get() {
                                    return "😈😈😈";
                              },
                        }
              
        
        
        
                  !14、侦听器 侦听data computed
        
                              watch: {
                                    数据名(newVal, oldVal){
                                          newVal 修改后的新值
                                          oldVal 上一次的值
                                    }
                              }
                              
                              侦听复杂数据
                              watch: {
                                    数据名: {
                                          deep: true, // 开启深度侦听
                                          handler(newVal, oldVal){},
                                          immediate: true 
                                    }
                              }
        
            */


      }
      {   //todo  Day-4
            /* 
        
                  ! 1、组件 全局与局部 components
                        组件：  是可以复用的vue实例，.vue 文件 （里面封装 标签 + css + js） 写到 components 文件夹中
                        
                        使用组件步骤
                              1. 创建vue组件
                              2. 引入组件
                              3. 注册组件
                                    3.1 全局注册   main.js 文件中
                                                Vue.component('组件名', 导入进来的组件对象)
                                                在任意的.vue文件中都可以使用 全局组件
        
                                    3.2 局部注册  
                                                 import 组件对象 from 'vue文件路径'
        
                                                      export default {
                                                      components:{
                                                            '组件名' ： 组件对象
                                                      }
                                                      }
                              4. 使用：  把组件名 当标签来使用
                                          双标签，单标签 都可以
        
                              5.哈希值 ：scoped  <style scoped> 
                                    vue组件内样式，只针对当前组件内标签生效， styple上添加 scoped 
                                    原理 ：自动添加哈希值
                                    
                              单向数据流 ：父级到子级的数据流向
        
                  ~ components   
                                语法  ：
                                    父组件内： @自定义事件名 = "父methods里函数名"
                                    子组件内：例如当点击事件触发时 用 this$emit("自定义事件名" ，值)
        
        
                                    1. 父组件通过 props 给子组件传递函数，子组件调用该函数即可修改父组件的数据   
                                                      2. 组件 methods 里函数的 this 始终指向该组件实例，可理解为 Vue 底层对这些函数做了bind处理  
                                                                        3. 通过bind修改 this 指向后的新函数，其 this 指向不能再次修改推荐使用自定义事件  
        
        
                              例如： 父级 有数据 price=100 所以代码就在父级书写  只能自己数据自己改
        
                              父组件传给子组件的是一个对象 ，子组件修改对象属性 是不会报错的 对象是引用类型相互更新
        
                  ~2、组件内通信 
                        1. 父传子
                                    1.1 在子组件上，通过 props 来指定 属性，将来通过属性来接受父传给子的数据
                                                props: ['title', 'price']
                                    1.2 在父组件上，通过属性来传值
                                                <MyProduct title="哈哈，真好吃" :price="demo"></MyProduct>
        
                        2. 子传父
                                    1.1 在子组件上， 通过 this.$emit('自定义事件', 值) 触发自定义事件, 以及还可以传参
                                    1.2 在父组件上， 监听自定义事件
                                                <MyProduct @自定义事件="事件处理函数"></MyProduct>
                                  
        
            */
      }
      {   //todo  Day-5 生命周期
            /* 
            组件核心：便于复用
           !1、 生命周期 && 钩子函数
                  生命周期: vue实例 (vue组件》从创建到销毁的阶段过程
                  vue内置的函数，到了对应的阶段会自动的去执行对应的钩子函数(在特定的时刻调用特定的函数 )钩子函数:
        
                  4大阶段，8个钩子函数beforeXXXxxxx d
                        初始化 :beforeCreate   created
                        挂载   :beforeMount    mounted
                        更新   :beforeUpdate   updated
                        销毁   :beforeDestroy  destroyed
        
                        实际工作中created && mounted
                        created使用场景:发送ajax请求(请求越早发送越好)，获取到数据添加到data的数据中mounted使用场景:可以去获取真实的DOM元素了
                        
            组件 name 属性，可以作为组件名来使用
                  components: {
                        注册
                        [组件对象.name]: 组件对象
                  }
        
             !2、ref 属性
                  1.获取DOM 元素，去使用DOM 元素的属性、方法。比如:获取到输入框，使其调用focus() 方法，实现获取焦点
                  2.获取组件对象，可以去使用组件内的方法
                  this.$refs.xxx
        
                 
                nextTick    数据了发生了改变，vue中DOM更新是异步的,想要获取到更新后DOM，需要借助于
                nextTick  两种方法：
                                    1.$nextTick1. this.$nextTick(() => [ ... })
                                    2. await this .$nextTick()
        
            
            
            */
      }
      {   //todo  Day-6 动态组件 插槽 创建自定义指令

            /* 
        !一、动态组件与缓存   
                        动态组件 :
                                    什么是动态组件   :在同一个挂载点, 可以切换显示不同组件
                                    如何使用动态组件 :vue内置的component组件, 配合is属性
                                    如何切换        :改变is属性的值, 为要显示的组件名即可
        
                                    语法:
                                          <button @click="comName = 'UserInfo'">个人信息填写</button>
                                          <component :is="comName"></component>
        
        
                        组件缓存
                                    <keep-alive> </keep-alive>
                                    好处:
                                    不会频繁创建于销毁 组件 页面更快呈现出来
                                    如何进行组件缓存 :
                                          vue内置的keep-alive组件把要缓存的组件包起来
        
                        组件激活和非激活
                              目标：扩展2个新的生命周期方法  
        
                              如何知道缓存的组件是出现还是消失了（如何知道组件被切走了, 还是切换回来了呢?）?
                              方法名:
                                    activated – 激活时触发
                                    activated(){}
        
                                    deactivated – 失去激活状态触发
                                    deactivated(){}
        
        
        !二 . 插槽
                        1.什么是插槽:                        
                                    子组件提供给父组件使用一个占位符slot,
                                    父组件可在slot中填充任何模板代码，如 HTML、组件等，
                                    填充的内容会替换子组件中的<slot></slot>标签。
        
                        2.作用 :   提高组件的重用能力
                         
                        2.插槽的种类:
                                    *组件插槽:没给插槽slot起名字,也叫默认插槽
                                    *具名插槽:给slot起名字(定义具名插槽:使用到name特性)
                                    *作用域插槽:本质是携带信息的匿名插槽
        
                             ~1.组件插槽
                                    1. 组件内 <slot></slot> 占位
                                    2. 使用组件, 传入具体的标签替换 到slot位置上
                             ~2.具名插槽
                                    场景:  2处以上不确定的地方
                                    1. 子组件 :slot占位 - name属性起名字
                                    2. 使用组件. template配合 v-slot:插槽名, 夹着传入具体标签  
                             ~3.作用域插槽
                                    场景: 父组件使用插槽技术时, 要使用子组件内的变量
                                    1. slot标签, 自定义属性和内变量关联 (子组件在slot 上添加属性与子组件值)
                                    2. 父组件使用组件, template配合v-slot="变量名"
                                          变量名会收集slot身上属性和值形成对象
                                    3. 子组件slot 同时有name  与自定义属性时 父组件可以 使用 #nam名 变量名
        
        
        !三 .  创建自定义指令
                                    *全局 / 局部
                                    *2. 在标签上使用自定义指令  v-指令名
                                    全局指令:
                                          Vue.directive('指令名', {})
                                    局部指令
                                          directives: {
                                                focus 指令名 在标签上 使用 v-focus
                                                focus: {
                                                inserted(el) {
                                                      el形参表示指令所在的DOM元素
                                                console.log(el);
                                                      el.focus(); //focus 获取焦点
                                                      },
                                                },
                                                },
            */
      }
      {   //todo  Day-7  

            {//!一.路由使用步骤:
                  /* 
                                    .下载         yarn add vue-router@3
                                   1.引入         import VueRouter from 'vue-router'
                                   2.注册全局组件  Vue.use(VueRouter)
                                   3.规则数组      const reutes =[
                                                                 { 
                                                                 panth:'/find' ,   //路由路径
                                                                 conponent:Find    //组件      路由是路径与组件的映射关系      
                                                                 },           
                                                                 {
                                                                 path: "*",            // ...省略了其他配置
                                                                 component: NotFound   //404在最后(规则是从前往后逐个比较path 当前面都没有时显示404)
                                                                 }   
                                                                 ]
                                   4.创建路由 实例对象  const router = new VueRouter({
           
                                                           // routes:routes,
                                                           routes, //简写 哈希字符串   由规则数组来
                                                           mode: "history",// 打包上线后需要后台支持, 模式是history模式 不带#号
           
                                                           // // 配置高亮效果
                                                           // linkActiveClass:'aa',
                                                           // linkExactActiveClass: "bb"
                                                     })
                                   5.路由守卫  :创建路由实例对象后  路由守卫才可以拿到 
           
                                               场景: 当你要对路由权限判断时
                                               语法: router.beforeEach((to, from, next)=>{//路由跳转"之前"先执行这里, 决定是否跳转})
                                               参数1: 要跳转到的路由 (路由对象信息)    目标
                                               参数2: 从哪里跳转的路由 (路由对象信息)  来源
                                               参数3: 函数体 - next()才会让路由正常的跳转切换, next(false)在原地停留, next("强制修改到另一个路由路径上")
                                               注意: 如果不调用next, 页面留在原地
           
                                               例子: 判断用户是否登录, 是否决定去"我的音乐"/my
                                               let isLogin = false
                                               router.beforeEach((to, from, next) => {
                                                     console.log(to);    // 去哪 路由信息
                                                     console.log(from);  // 从哪来 
                                                     console.log(next);  // 决定去留函数   
                                   
                                                     // !  注意： next函数一定要调用 ，否则页面留在原地
                                               if (to.path === "/my" && isLogin === false) {
                                               
                                                     alert("请登录")     未登录 想去 我的音乐界面 不让去，留在原地 next(false)
                                                     next(false)         阻止路由跳转
                                                                       *next('/login') //next(强制跳转到临海一个路由路径上)
                                               } else {
                                                     next() // 正常放行
                                               }
                                         })
                                   6.路由对象 注入到vue实例中 
                                         Vue.config.productionTip = false
                                         
                                         new Vue({
                                               // router:router,
                                               router, // 简写
                                               render: (h) => h(App),
                                         }).$mount('#app')
          
                                    7.设置挂载点: <router-view> </router-view>
                                                ~设置挂载点后 在main.js 把    3.规则数组中的页面组件引到main.js里
           
           
                 */
            }
            /* 
            !一 . 路由
                  1.路由组件 :
                              * 页面组件 - 页面展示 - 配合路由用
                              * 复用组件 - 展示数据/常用于复用   
                  2.步骤    :
                              .下载         yarn add vue-router@3
                              1.引入         import VueRouter from 'vue-router'
                              2.注册全局组件  Vue.use(VueRouter)
                              3.规则数组      const reutes =[{}]
                              4.路由对象  创建路由 实例对象  const router = new VueRouter({})
                              5.路由守卫  :创建路由实例对象后  路由守卫才可以拿到 
                              6.路由对象 注入到vue实例中 
                              7.设置挂载点: <router-view> </router-view>
                              ~设置挂载点后 在main.js 把    3.规则数组中的页面组件引到main.js里
        
                  3.规则何时生效;
                              切换到url 上hash值时开始匹配规则数组  对应组件展示到 <router-view></router-view> 上      
        
            !二 . 声明式导航  编程式导航
                  ~ 声明式导航:   router-link 自带高亮效果  (自带类名)
        
                              1. 挂载点 vue-router提供了一个全局组件 router-link
        
                              1、query    /part?参数名=值      $route.query.参数名
                              2、params   /pert/直接书写的值   $route.params.参数名
                                          前提是需要在全局（main.js）路由规则中配置 /part/:参数名
                              3、重定向 ： 定义默认打开页面    
                                          （main.js）规数组中定义 path:/     redirect配置项 ：值  为强制更换的路径 
                              4、404       3.规则数组  
                              5、路由切换为 history模式  不带#号
        
                        实例:
                              <router-link to="/my">我的音乐</router-link>
                              <router-link to="/part?username=你想起舞么！">朋友</router-link>
        
                  ~编程式导航:
                               目标: 编程式导航 - 跳转路由传参
                              语法:
                                   this.$router.push({path:'路由路径'})
                                   this.$router.push({name:'路由名'})
        
                              方式1:   params => $route.params.参数名
                              方式2:   query => $route.query.参数名
        
                              重要: path会自动忽略params
                              推荐: name+query方式传参
                              注意: 虽然用name跳转 ,但是 url的hash值韩式切换path路径值
        
        
            
        
        
        
        
        
        
        
            
            */
      }
      {   //pink  vue固定语法

            /* 
            todo  
        
        
                        1、            语法  ：menods {}  data函数内返回的对象
                                    
                                    
                        2、过滤器       语法 ：filters: {
                                          //      传入变量的函数
                                                toUp(val) {
                                                      return val.toUpperCase();
                                                      },
                                                }
        
                        3、计算属性     语法 ：computed：{                             提供计算属性的时候，写函数形式，使用计算属性的时候当属性使用
                                                计算属性名(){                         普通使用可以 {{在插值表达式里使用}}   
                                                            return "值"               计算属性 ：一个变量的结果依赖于其他的变量计算出来
                                                      }
                                                }   
                                         
        
                        4、监听器       语法 ：     watch: {
                                                      "要侦听的属性名": {
                                                      immediate: true, // 立即执行
                                                      deep: true, // 深度侦听复杂类型内变化    
        
                                                      handler (newVal, oldVal) {
                                                      }                newVal: 当前最新值
                                                   }                   oldVal: 上一刻的值
                                                }
                                                简单数据类型：只要 hanler:
                                                                        handler: 固定方法触发. 侦听函数必须叫handler(必写)
                                                复杂数据类型 ：都要加    ：
                                                                        deep: 开启深度侦听(必写)   监听data里属性的值（对象、数组）
                                                                        immediate: 立即侦听(页面初始化时handler立即执行一次)
                        
                        5、组件         components
            */
      }
      {   //todo  js Array常用方法
            /*      
            br 
            gr
            pink
            blue
                       ===（恒等）    比较两个操作数的值是否相等，同时检测它们的类型是否相同         相等是true
                      ！==（不恒等）  比较两个操作数的值是否不相等，同时检测它们的类型是否不相同      相等是false                         
        
        
                        filter    筛选符合条件的 每一项 ,没找到返回undf
                        find      查找 符合条件 的每一项  find 是查找符合条件的那一项，并返回找到的结果，并不会返回新数组哈
                        findIndex 查找下标
        
                        reduce((sum ,obj) ={ sum = sum + obj.price , 0})   累计求和方法；               
                                                                              1、sum 累计的变量
                                                                              2、obj 遍历的对象
                                                                              3、0   初始值
                         对arr数组每一项进行遍历 修改每一项 c属性值和全选值一样
                         this.arr.forEach((item) => (item.c = val));         //16
        
            */
      }
      {   //todo  包
            /*
        
            style 标签 lang="less"    
            需要装包  yarn add less less-loader -D  重启服务器
            
        
            1、    bootstrap  框架包
                  安装   yarn add bootstrap@4    版本4
                  全局导入   import "bootstrap/dist/css/bootstrap.css"     在 main.js入口文件文件   以import引入
        
        
            2、Animate.css 动画效果包
                  安装           yarn add animate.css
                  全局/局部导入  import 'animate.css';
                  使用          <h1 class="animate__animated animate__bounce">前面是固定格式 后面是效果</h1>
        
            
            3 路由 vue-routre@3 是配合vue2使用
                  安装    yarn add vue-router@3
                  导入    import VueRouter from 'vue-router'
                  使用    Vue.use(VueRouter)    // 在vue中，使用使用vue的插件，都需要调用Vue.use()
        
        
        
            
            !二、vuex2 包
            1、vuex包  vue@2 
                  安装   yarn add vuex@3
               
        
        */

      }

}

{   //todo  vuex 步骤  state  严格模式  mutations  actions   getters  模块化（命名空间）

      {  // todo   vuex总结
            /* 
      ! 整理辅助函数书写位置
        四个辅助函数都是从vuex中导入的
            import { mapState, mapMutations, mapActions, mapGetters  } from 'vuex'
        
            !                        computed: {
            ~ 公共数据源     state               ...mapState(['state数据名'])


            ~ 计算属性       getters             ...mapGetters(['getters 属性名'])
                                                ~语法：this.$store.getters.属性名
                                         }      
                              

            !                        methods: {
            ~ 修改state数据   mutations          ...mapMutations(['mutations方法名']), 
                                                ~语法：this.$store.commit('addMoney', 值)

            ~ 异步操作        actions            ...mapActions(['actions方法名'])
                                                ~语法：this.$store.dispatch('actions方法名', 值) 
                                          }    
            */
      }
      /* \
        vue2: vue-roter@3 vuex@3 233
        vue3: vue-roter#4 vuex#4 344
  
        vant 移动端组件库  推荐pinia 比vuex简单点
    
          ! vuex 是啥？  
              是vue中的状态管理工具     状态既数据  共享的通用的数据放到vuex的仓库中
      
          ! vuex 使用步骤
              1. 下包  yarn add vuex@3
              2. 新建  store/index.js
              3. index.js 代码
                        // 导入vue
                        import Vue from 'vue'
                        // 导入vuex
                        import Vuex from "vuex"
                        // vuex是vue插件 需要use  进行插件初始化
                        Vue.use(Vuex)

                        // 创建仓库 store
                        const store = new Vuex.store({

                        })

                        // 导出 store
                        export default store
                      
              4. main.js 导入并注入到vue实例中
                      import store from '@/store'
      
                      new Vue({
                          store
                      })
      
          !1、核心概念 state
             作用：State提供唯一的公共数据源，所有共享的数据都要统一放到Store中的State中存储
      
             语法：
                  new Vuex.Store({
                     ~ state: {
                          money: 100,
                          xxxx
                      }
                  })
      
             使用：
                  方式1. 模板中使用 {{ $store.state.money }}

                  方式2. 提供计算属性
                         computed: {
                              手动提供计算属性
                              money(){
                                  return this.$store.state.money
                              }
                         }
                  方式3： 辅助函数 mapState
                         1. 是函数
                         2. 参数可以是数组、对象
                         3. 返回值是个对象
                         4. 作用：可以自动把state中的数据映射作为组件内的计算属性
      
                     语法：
                         导入import {mapState} from 'vuex'
                              computed: {
                        数组方法        ...mapState(['money']),     

                        对象方法        ...mapState({
                                                nameMap: "name",
                                           可以很方便的决定计算属性的名字
                                           计算属性名: 'state中数据'
                                      }),
                              }
          
          !1、 开启严格模式 ：开发环境
                        development ；开发环境
                        production  : 生产环境 发布后才启用

                        process：全局变量  env：拿到NODE_ENV   
                        ~语法 ：strict: process.env.NODE_ENV === 'development',
                        
                        ~开启严格模式后 改数据只能在 ：mutations里改数据
            
                        
          !2 state 数据
                  作用 ：1、所有数据都写到state中 共享vuex通用数据
                         ~state: 状态 即数据 state指的是vuex中的数据
                  语法：
                        new Vuex.Store({
                        state: {
                              money: 100,
                              xxxx
                        }
                        })

                  使用：
                        方式1. 模板中使用 {{ $store.state.money }}
                        方式2. 提供计算属性
                              computed: {
                                    手动提供计算属性
                                    money(){
                                    return this.$store.state.money
                                    }
                              }
                        方式3： 辅助函数 mapState
                              1. 是函数
                              2. 参数可以是数组、对象
                              3. 返回值是个对象
                              4. 作用：可以自动把state中的数据映射作为组件内的计算属性

                                    computed: {
                                          ...mapState(['money']),
                                          ...mapState({
                                                可以很方便的决定计算属性的名字
                                                计算属性名: 'state中数据'
                                          }),
                                    }

                  拿数据：  导入import {mapState} from 'vuex'

                  计算属性       computed: {
                        数组方法        ...mapState(['money']),     

                        对象方法        ...mapState({nameMap: "name", }) 
                                        }     


                      
          !3、 mutations
                  语法：
                      gr  提交的参数只能是一个, 如果有多个参数要传, 可以传递一个对象**
                      gr  payload 载荷 指的就是mutations的额外参数，payload是一个对象，因为可以传递多个参数，而且更好阅读

                    作用：提供修改state数据的方法

                  语法：
                        mutations: {
                        addMoney(state, val){
                              mutations方法的第一个参数都是 state
                              第二个参数接收到的值
                              state.money += val
                        }
                        }

                  使用：
                        方式1：this.$store.commit('addMoney', 值)
                        方式2：辅助函数 mapMutations
                              methods: {
                              ...mapMutations(['addMoney'])
                              }
                              this.addMoney()
                              等价于
                              methods: {
                              ...{
                                    addMoney(){
                                          this.$store.commit('addMoney', 值)
                                    }
                              }
                              }
                  
                  
                  注意点：
                        1. mutations 不能异步的修改state数据，异步借助于 actions 
                        2. mutations: {
                              addMoney(state, val){
                                    如果要接收多个参数，传对象形式，传递多个数据
                              }
                        }

                        
                  简写：                        
                      import { mapMutations } from "vuex";
                      ...mapMutations(["addFnMoney", "addFnMoneyFn"]),

                      
          
          !4、 actions  异步代码   注意：actions不能直接修改数据   只能mutations改
                  ~state是存放数据的，
                  ~mutations是同步更新数据 (便于监测数据的变化, 更新视图等, 方便于调试工具查看变化)，
                  ~actions则负责进行异步操作  
                  
            语法：
                  actions: {
                  addMoneyAsync(context){
                        actions方法的第一个参数都是context（等价于 store）

                        异步代码（ajax请求）
                        context.commit('mutations方法名', 值)
                  }
                  }
            
            使用：
                  方式1：this.$store.dispatch('actions方法名', 值)
                  方式2：辅助函数 mapActions
                        methods: {
                              ...mapActions(['actions方法名'])
                        }


                        
          !5、 getters

            作用：vuex中的计算属性（可以把组件共享的计算属性写到 getters中）

            语法：
                  getters: {
                  nickname(state) {
                        // 第一个参数是state
                        return state.money >= 102 ? '土豪' : 'DS'
                  },
                  },       

            使用：
                  方式1：this.$store.getters.nickname
                  方式2：辅助函数 mapGetters
                        computed: {
                        ...mapGetters(['getters属性名'])
                        }            

          !6、模块化


            命名空间：开启了命名空间 mutations  actions  getters  都调用不了了
                    namespaced: true,
                    新建 store/modules 目录 放子模块
        
            new Vuex.Store({
                  modules: {
                  模块名: 导入的模块对象
                  }
            })

            子模块写啥
                  export default {
                  state: {},
                  getters: {},
                  mutations: {},
                  actions: {},
                  }

                  但： 子模块内的getters  mutations actions 都挂载全局中
                  希望是挂载到子模块内使用，是子模块中 开启 命名空间  namespaced: true

            使用state：     $store.state.模块名.state数据名
            使用mutations   $store.commit('模块名/mutations方法名')
            使用actions     $store.dispatch('模块名/actions方法名')
            
             辅助函数
            computed: {
                ...mapState('模块名', ['state数据名']),
                ...mapGetters('模块名', ['getters数据名']),
            }
            methods: {
                ...mapMutations('模块名', ['mutations方法名']),
                ...mapActions('模块名', ['actions方法名']),
            }

                     

          
      
      */

}